<?php
/**
 * Created by PhpStorm.
 * User: Inhere
 * Date: 2015/3/4
 * Time: 19:44
 * Usage : 一张表的信息数据，包含了对当前表的各种操作，字段信息， 架构信息(Schema)
 * File: AbstractTable.php
 */

namespace ulue\core\db\base\command;

use ulue\core\db\base\AbstractDbDriver;
use ulue\core\db\base\InterfaceTable;
use ulue\core\db\base\schema\Schema;

abstract class AbstractTable extends AbstractCommand implements InterfaceTable
{
    /**
     * Property database. database name.
     * @var  string
     */
    protected $database;

    /**
     * Property name. table real name
     * @var  string
     */
    protected $name;

    /**
     * Property fullName. has database name; e.g. 'dbName.tableName'
     * @var  string
     */
    protected $fullName;

    /**
     * Property schema.
     * 当前表的架构信息
     * @var  Schema
     */
    protected $schema = null; //array();

    /**
     * Property ifNotExists.
     * @var  boolean
     */
    // protected $ifNotExists = null;

    // 创建表sql代码
    protected $createCode = '';

    protected $describe;

    // 主键字段
    protected $priKey;


    public function __construct($name='', AbstractDbDriver $db)
    {
        if ($name) {
            $this->resolveName($name);
        }

        $this->db   = $db;
    }

    protected function resolveName($name)
    {
        $parts = explode('.', str_replace('`', '', $name));

        if (isset($parts[1])) {
            $this->database = $parts[0];
            $this->name     = $parts[1];
            $this->fullName = $this->database . '.' . $this->name;
        } else
        {
            $this->fullName = $this->name = $parts[0];
        }
    }

//////////////////////////////////////////////// table operate ////////////////////////////////////////////


    abstract public function create($ifNotExists = false, array $options = []);

    abstract public function doCreate(
        $columns, array $pks = [], array $keys = [], $autoIncrement = null, $ifNotExists = true,
         $engine = 'InnoDB', $defaultCharset = 'utf8', $collate = 'utf8_general_ci'
        );

    /**
     * @param bool $ifNotExists
     * @param string $option
     * @return $this
     */
    abstract public function drop($ifNotExists = true, $option = '');

    // 更新表结构信息
    abstract public function update();

    /**
     * save
     * @param bool  $ifNotExists
     * @param array $options
     * @return  static
     */
    abstract public function save($ifNotExists = true, array $options = []);

    /**
     * reset
     * @return  static
     */
    abstract public function reset();

    abstract public function rename($newName, $returnNew = true);

    abstract public function lock();

    abstract public function unlock();

    abstract public function truncate();

//////////////////////////////////////////////// table info ////////////////////////////////////////////

    abstract public function getDetail($refresh=false);

    /**
     * getSchema
     * @param bool $refresh
     * @return Schema
     */
    abstract public function getSchema($refresh=false);

    /**
     * @param null $field
     * @return null
     */
    public function getDescribe($field=null)
    {
        if ($field===null)
        {
            return $this->describe;
        }

        return isset($this->describe[$field]) ? $this->describe[$field] : null;
    }

    abstract public function getCreateCode();

    public function getPriKey()
    {
        return $this->priKey;
    }


//////////////////////////////////////////////// index info ////////////////////////////////////////////

    /**
     * addIndex
     *
     * @param string $type
     * @param string $name
     * @param array  $columns
     * @param string $comment
     * @param array  $options
     *
     * @return  static
     */
    abstract public function addIndex($type, $name = null, $columns = array(), $comment = null, $options = array());

    /**
     * dropIndex
     *
     * @param string  $type
     * @param string  $name
     *
     * @return  static
     */
    abstract public function dropIndex($type, $name);

    /**
     * getIndexes
     *
     * @return  static
     */
    abstract public function getIndexes();

//////////////////////////////////////////////// column info ////////////////////////////////////////////

    abstract public function existsColumn($name);

    abstract public function getColumnNames($toString=false);

    abstract public function getColumnDetails($full = true);

    abstract public function getColumnDetail($column, $full = true);


//////////////////////////////////////////////// column operate ////////////////////////////////////////////


    public function setCollate($table, $charset='utf8_general_ci')
    {
        # code...
        return 'ALTER TABLE ' . $this->qn($table) .' COLLATE=' . $charset;
    }

    public function editColumn($value='')
    {
        return '';
    }

    public function updateColumn($value='')
    {
        return $this->editColumn();
    }


    /**
     * addColumn
     *
     * @param string $name
     * @param string $type
     * @param bool   $signed
     * @param bool   $allowNull
     * @param string $default
     * @param string $comment
     * @param array  $options
     *
     * @return  static
     */
    abstract public function addColumn($name, $type = 'text', $signed = true, $allowNull = true, $default = '', $comment = '', array $options = []);

    public function alterColumn($value='')
    {
        # code...
    }

    /**
     * dropColumn
     * @param string $name
     * @return  mixed
     */
    abstract public function dropColumn($name);

//////////////////////////////////////////////// other ////////////////////////////////////////////


    public function getDatabase()
    {
        return $this->database;
    }

    public function getFullName()
    {
        return $this->fullName;
    }

    // public function setFullName($name)
    // {
    //     $this->resolveName($name);

    //     return $this;
    // }

    /**
     * Method to set property table
     * @param   string $name
     * @return  static  Return self to support chaining.
     */
    // public function setName($name)
    // {
    //     $this->resolveName($name);

    //     return $this;
    // }

}// end class AbstractTable